unit Interface_WndMain;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ScktComp, StdCtrls, ComCtrls, ExtCtrls, ClipBrd;

type
  TWndDownload = class(TForm)
    txtUrl: TLabeledEdit;
    ProgressBar: TProgressBar;
    Button: TButton;
    ClientSocket: TClientSocket;
    StatLabel: TLabel;
    Timer: TTimer;
    Memo: TMemo;
    StopButton: TButton;
    StatusBar: TStatusBar;
    BpsTimer: TTimer;
    procedure ButtonClick(Sender: TObject);
    procedure ClientSocketConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocketRead(Sender: TObject; Socket: TCustomWinSocket);
    procedure ClientSocketDisconnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure FormShow(Sender: TObject);
    procedure ClientSocketConnecting(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure TimerTimer(Sender: TObject);
    procedure StopButtonClick(Sender: TObject);
    procedure BpsTimerTimer(Sender: TObject);
  private
    procedure ParceAddress(url : String);
  public
    { Public declarations }
  end;

var
  WndDownload: TWndDownload;
  url, proto, host, port, get, FileName : String;
  FileStr : TFileStream;
  WriteFil : Boolean = False;
  Total : Cardinal = 0;
  Done  : Cardinal = 0;
  BCount : Cardinal = 0;

implementation
uses
  AppInterface;

{$R *.dfm}

procedure TWndDownload.ButtonClick(Sender: TObject);

begin
  txtUrl.Enabled := False;
  Button.Enabled := False;
  port := '80';

  ParceAddress(txtUrl.Text);

  FileName := get;

  while Pos('/', FileName) <> 0 do
  begin
    Delete(FileName, 1, Pos('/', FileName));
  end;

  if Pos('?', FileName) <> 0 then
    FileName := Copy(FileName, 1, Pos('?', FileName)-1);

  FileName := InputBox('File name', 'Change file name?', FileName);

  FileName := AppFace.UI_GetActiveList^.Path + FileName;

  FileStr := TFileStream.Create(FileName, fmCreate);

  AppFace.ConsolePrint(PChar('Downloading to: ' + FileName));

  AppFace.UI_UpdateLists;

  ClientSocket.Host := host;
  ClientSocket.Port := StrToInt(port);
  ClientSocket.Active := True;

  StatLabel.Caption := 'Start...';
end;

procedure TWndDownload.ClientSocketConnect(Sender: TObject;
  Socket: TCustomWinSocket);
var
  Req : String;
begin
  StatLabel.Caption := 'GET ' + get;
  Req := 'GET ' + get + ' HTTP/1.1'#13#10 +
         'Host: ' + host + #13#10 +
         'User-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)' + #13#10 +
         'Accept: */*'#13#10;
  if Done <> Total then
  begin
    Req := Req + 'Content-Range: bytes ' + IntToStr(Done) + '-' + IntToStr(Total-1) + '/' + IntToStr(Total) + #13#10;
  end;
  Req := Req + 'Pragma: no-cache'#13#10 +
         'Connection: close'#13#10 +
         'Cache-Control: no-cache'#13#10#13#10;

  Memo.Text := Memo.Text + Req;

  Socket.SendBuf(Req[1], Length(Req));
end;

procedure TWndDownload.ClientSocketRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  Rec, Header, Head, Val : String;
  Buff : Pointer;
  DataLen : Cardinal;
begin
  DataLen := 0;
  

  if not WriteFil then
  begin
    Rec := Socket.ReceiveText;
    
    if Pos(#13#10#13#10, Rec) <> 0 then
    begin
      while Pos(#13#10#13#10, Rec)<>0 do
      begin
        Header := Copy(Rec, 1, Pos(#13, Rec)-1);

        Memo.Lines.Add(Header);

        Head := Copy(Header, 1, Pos(':', Header)-1);
        Delete(Header, 1, Pos(':', Header)+1);
        Val := Header;

        if LowerCase(Head) = 'content-length' then
        begin
          Total := StrToInt(Val);
          ProgressBar.Max := Total;
        end else
        if LowerCase(Head) = 'location' then
        begin
          get := Val;
          ClientSocket.Close;
          Timer.Enabled := True;
        end;

        Delete(Rec, 1, Pos(#13, Rec)+1);
      end;
      Delete(Rec, 1, 2);

      if Length(Rec) <> 0 then
      begin
        Buff := @Rec[1];
        DataLen := Length(Rec);
      end;
      WriteFil := True;
    end;
  end;

  if WriteFil then
  begin
    if DataLen = 0 then
    begin
      DataLen := Socket.ReceiveLength;
      GetMem(Buff, DataLen);
      Socket.ReceiveBuf(Buff^, DataLen);
    end;
    StatLabel.Caption := Format('%d Kb of %d Kb Recived', [Done div 1024, Total div 1024]);
    FileStr.Write(Buff^, DataLen);
    ProgressBar.StepBy(DataLen);
    Done := Done + DataLen;
    BCount := BCount + DataLen;
  end;
end;

procedure TWndDownload.ClientSocketDisconnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  FileStr.Free;
  StatLabel.Caption := 'Finished...';
  AppFace.UI_UpdateLists;
end;

procedure TWndDownload.FormShow(Sender: TObject);
var
  txt : String;
begin
  if Clipboard.HasFormat(CF_TEXT) then
  begin
    txt := Clipboard.AsText;
    if Pos('http://', txt) <> 0 then
      txtUrl.Text := txt;
  end;
end;

procedure TWndDownload.ClientSocketConnecting(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  StatLabel.Caption := 'Connecting ... ';
end;

procedure TWndDownload.TimerTimer(Sender: TObject);
begin
  ClientSocket.Active := True;
  Timer.Enabled := False;
end;

procedure TWndDownload.StopButtonClick(Sender: TObject);
begin
  if StopButton.Caption = 'STOP' then
  begin
    StopButton.Caption := 'RESUME';

    ClientSocket.Close;
  end else
  begin
    StopButton.Caption := 'STOP';

    ClientSocket.Open;
  end;
end;

procedure TWndDownload.ParceAddress(url: String);
begin
  proto := Copy(url, 1, Pos(':', url)-1);
  Delete(url, 1, pos(':', url)+2);

  if Pos(':', url) <> 0 then
  begin
    host := Copy(url, 1, Pos(':', url)-1);
    Delete(url, 1, Pos(':', url));
    port := Copy(url, 1, pos('/', url)-1);
    Delete(url, 1, Pos('/', url));
    get := '/' + url;
  end else
  begin
    host := Copy(url, 1, pos('/', url)-1);
    Delete(url, 1, POs('/', url));
    get := '/' + url;
  end;
end;

procedure TWndDownload.BpsTimerTimer(Sender: TObject);
begin
  StatusBar.SimpleText := IntToStr((BCount) div 1024) + 'Kb/s';
  if Total <> 0 then
    Caption := IntToStr(Done div (Total div 100)) + '% @ ' + StatusBar.SimpleText;
  BCount := 0;  
end;

end.
